#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* What we need */

#include "posets.h"
#include "commondefs.h"
#include "debug.h"

void 
poset_free(Poset *p)
{
  list_free(p->sss);
  free(p);
}

void
poset_set_name(char *name, Poset *p)
{
  strncpy(p->name,name, POSET_NAME_DIM);
}

int
poset_belongs(Subset s, Poset * p){
  
  Listofsss current;

  FORALLIN(current,p->sss)
    {
      if(ss_equal(&s,&current->el) )
	return 1;
    }
  
  return 0;

}

/** Add an element to Poset P. 
    This is done :
    - assuming P is topologically sorted
    - leaving P topologically sorted
*/
void
poset_ts_add_el(El a, Poset *p)
{
  if ( p->sss == NULL )
    {
      p->sss = list_append_element(a,NULL);
    }
  else
    {  
      Listofsss i;
    
     
      /** Find a right place where to insert the new element*/
      FORALLIN(i,p->sss)
	{
	  if(ss_contained(&a,&i->el) )
	    break;
	}
    
      if(i == NULL)
	p->sss = list_append_element(a,p->sss);
      else
	/** If a == i->el do nothing */
	if(!ss_contained(&i->el,&a))
	  p->sss = list_insert(a,i,p->sss);
    }

  return;
}

Poset *
poset_tsort_of(Poset *p)
{
  Poset * ret = NEW(Poset);
  Listofsss i;

  FORALLIN(i,p->sss)
    poset_ts_add_el(i->el,ret);

  poset_set_name(p->name,ret);

  return ret;
}


Poset *
poset_copy_of(Poset *p)
{
  Poset *ret = NEW(Poset);

  poset_set_name(p->name,ret);
  ret->sss = list_copy(p->sss);

  return ret;
}

/*  Reversing the order of a poset.
 */
Poset *
poset_opposite_of(Poset *p,char *name)
{
  Listofsss i;
  Poset * tmp = poset_copy_of(p);

  FORALLIN(i,tmp->sss)
    ss_complement(&i->el);
  
  poset_set_name(name,tmp);
  return poset_tsort_of(tmp);

}

void
poset_force_opposite(Poset *p)
{
  Listofsss i;

  FORALLIN(i,p->sss)
    ss_complement(&i->el);
}

Listofsss
poset_uppercovers(El s, Listofsss p)
{

  Listofsss j,tmp;
  Listofsss covers = NULL, 
    nongthan = NULL;
  
  if(p == NULL)
    return NULL;
  else
    {
      /* 
	 If the head of the list is striclty greater
	 than s, then: 
      */
      if(ss_contained(&s, &p->el) && 
	 !ss_contained(&p->el,&s) )
	{	  
	  /* s has the to be a cover, since the 
	     Poset is topologically sorted */
	 	  
	  /* Filter out the elements 
	     that are not greater than the head */
	  for(j = p->next; j != NULL; j=j->next)
	    {
	      if(!ss_contained(&p->el, &j->el))
		{
		  nongthan = list_prepend_element(j->el,nongthan);
		}
	      
	    }
	  /* Restore the fact that the list is topologically sorted */
	  tmp = list_copy_reverted(nongthan);
	  list_free(nongthan); 
	  nongthan= tmp;
	  

	  /* Filter out the other upper covers from this list */
	  tmp = poset_uppercovers(s, nongthan);
	  covers = list_prepend_element(p->el,tmp);
	  
	  list_free(nongthan);
	}
      else
	covers = poset_uppercovers(s, p->next);
    }

  return covers;
}


/*  Printing Stuff */
void
poset_print_latdraw(Poset *p)
{
  Listofsss  i,j,ucovers;
  
  printf("( %s\n",p->name);
	
  FORALLIN(i,p->sss)
    {
      /* We do not need to make copies  */
      /* since the uppercovers create a new list  */
	      
      /* copy = list_copy(i->next); */
      ucovers = poset_uppercovers(i->el,i->next); 
      /* list_free(copy); */

      printf("  (  ");
      ss_print_name(&i->el);
      printf(" ");
      
      printf("(");
      
      FORALLIN(j,ucovers)
	{
	  printf(" ");
	  ss_print_name(&j->el);
	  printf(" ");
	}
      
      printf(") )\n");
      
      list_free(ucovers);
    }
  
  printf(")\n");

}


